<?php

namespace App\Trip;

use Carbon\Carbon;
use Exception;
use Illuminate\Http\UploadedFile;
use Intervention\Image\Facades\Image;
use Storage;

class UploadService
{

    private const DISABLE_MIMES = ['php', 'text', 'zip', 'application'];
    private bool         $tailor = false;// 是否裁剪
    private float|null   $width  = null; // 宽
    private float|null   $height = null; // 高
    private float|null   $x      = null; // 坐标 x
    private float|null   $y      = null;
    private string       $file_name;
    private string|false $file_content;

    /**
     * @param bool $tailor
     */
    public function setTailor(bool $tailor): self
    {
        $this->tailor = $tailor;
        return $this;
    }

    /**
     * @param float|null $width
     */
    public function setWidth(?float $width): self
    {
        $this->width = $width;
        return $this;

    }

    /**
     * @param float|null $height
     */
    public function setHeight(?float $height): self
    {
        $this->height = $height;
        return $this;
    }

    /**
     * @param float|null $x
     */
    public function setX(?float $x): self
    {
        $this->x = $x;
        return $this;
    }

    /**
     * @param float|null $y
     *
     */
    public function setY(?float $y): self
    {
        $this->y = $y;
        return $this;
    }

    /**
     * @throws Exception
     */
    public function upload(UploadedFile $file, string $business): self
    {
        $this->validBusiness($business);
        $mime      = $file->getClientMimeType();
        $fileSize  = $file->getSize();
        $extension = $file->getClientOriginalExtension();
        $isImage   = (bool)stristr($mime, 'image');
        $isVideo   = (bool)stristr($mime, 'video');

        foreach (self::DISABLE_MIMES as $disable) {
            $error = stristr($mime, $disable);
            if ($error) {
                throw new Exception('不支持的文件类型');
            }
        }

        //获取上传图片的临时地址
        $tmpPath = $file->getRealPath();
        $max     = 20;
        if (($fileSize > $max * 1024 * 1024)) {
            throw new Exception('文件不能大于'.$max.'M,请重新上传');
        }


        if (($fileSize > $max * 1024 * 1024) && $isVideo) {
            throw new Exception('视频文件太大,不能大于'.$max.'请重新上传');
        }

        if ($isImage) {
            if (($fileSize > 2 * 1024 * 1024)) {
                throw new Exception('图片太大,不能大于2M,请重新上传');
            }

            if ($this->width && $this->height && $this->x && $this->y) {
                Image::make($tmpPath)->crop($this->width, $this->height, $this->x, $this->y)->save($tmpPath);
            }

            try {
                $mime = Image::make($tmpPath)->mime();
            } catch (Exception $exception) {
                throw new Exception('未知图片文件');
            }

        }
        //生成文件名
        $this->file_name    = $this->buildFileName($file, $business);
        $this->file_content = $tmpPath;
        return $this;
    }

    /**
     * @throws Exception
     */
    private function validBusiness(string $business)
    {
        $b = explode('/', $business);
        if (!in_array($b[0] ?? '', config('upload.businesses'))) {
            throw new Exception("不支持的配置");
        }
    }

    private function buildFileName($file, string $business): string
    {

        $env       = app()->environment();
        $date_path = Carbon::now()->format('Y-m/d');
        $date      = Carbon::now()->format('Ymd');
        $now       = Carbon::now()->timestamp;
        $rand_str  = random_number(5);
        $extension = $file->getClientOriginalExtension();
        $fileName  = $rand_str.$file->getFilename().$now.$date.'.'.$extension;
        $pathName  = "{$business}/{$date_path}/".$fileName;
        return $env ? $env."/".$pathName : $pathName;
    }

    /**
     * @return string
     */
    public function getFileName(): string
    {
        return $this->file_name;
    }

    public function getLocalUrl()
    {
        Storage::put($this->file_name, $this->file_content, 'public');
        return Storage::url($this->file_name);
    }

    /**
     * @return false|string
     */
    public function getFileContent(): bool|string
    {
        return file_get_contents($this->file_content);
    }
}